package com.tma.serviceclientapp;

import java.util.List;

import a.location.LocationUtil;
import a.location.MyLocation;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.ProgressDialog;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ToggleButton;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.tma.demoservice2.location.ILocationTracerService;

public class MainActivity extends MapActivity implements OnClickListener {
    private static final String TAG = "MainActivity";
    private static final String SERVICE_NAME = "com.tma.demoservice2.location.LocationTracerService";

    private MapView mMapView;
    private ToggleButton mStatusToggleButton;
    private ToggleButton mBindToggleButton;
    private Button mLoadButton;

    private boolean mBound = false;
    private ILocationTracerService mService;
    private RefreshHandler mRefreshHandler;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: " + name);
            mService = null;
        }

        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected:" + name);
            mService = ILocationTracerService.Stub.asInterface(service);
            mStatusToggleButton.setChecked(true);
            mLoadButton.setEnabled(true);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapView = (MapView) findViewById(R.id.mv_map);
        mStatusToggleButton = (ToggleButton) findViewById(R.id.tbtn_service_status);
        mBindToggleButton = (ToggleButton) findViewById(R.id.btn_bind_service);
        mLoadButton = (Button) findViewById(R.id.btn_load_location);

        mBindToggleButton.setOnClickListener(this);
        mLoadButton.setOnClickListener(this);

        mRefreshHandler = new RefreshHandler(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mBound) {
            unbindService();
        }
        mRefreshHandler.requestStop();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //bindService();
        mRefreshHandler.requestRefresh();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_delete_locations:
            DeleteLocationsTask task = new DeleteLocationsTask();
            task.execute();
            break;

        default:
            break;
        }
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        MenuItem item = menu.findItem(R.id.menu_delete_locations);
        item.setEnabled(mBound);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_bind_service:
            if (mBindToggleButton.isChecked()) {
                bindService();
            } else {
                unbindService();
                mLoadButton.setEnabled(false);
            }
            break;
        case R.id.btn_load_location:
            LoadLocationTask task = new LoadLocationTask();
            task.execute();
            break;
        default:
            break;
        }
    }

    private void updateServiceStatus() {
        boolean running = isServiceRunning(SERVICE_NAME);
        mStatusToggleButton.setChecked(running);
        mBindToggleButton.setChecked(mBound);
        mBindToggleButton.setEnabled(running);
        mLoadButton.setEnabled(mBound);
    }

    private void bindService() {
        Intent intent = new Intent(ILocationTracerService.class.getName());
        mBound = bindService(intent, mServiceConnection, Service.BIND_AUTO_CREATE);
    }

    private void unbindService() {
        if (mBound) {
            unbindService(mServiceConnection);
            mBound = false;
        }
    }

    private boolean isServiceRunning(String serviceName) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningServiceInfo> services = manager.getRunningServices(Integer.MAX_VALUE);
        for (RunningServiceInfo service : services) {
            if (serviceName.equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    private class DeleteLocationsTask extends AsyncTask<Void, Void, Void> {
        private ProgressDialog mProgressDialog;

        @Override
        protected void onPreExecute() {
            mProgressDialog = ProgressDialog.show(MainActivity.this,
                    "Invoke Service", "Loading location...");
        }

        @Override
        protected Void doInBackground(Void... params) {
            try {
                mService.removeAll();
            } catch (RemoteException e) {
                Log.e(TAG, e.getMessage(), e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            mProgressDialog.cancel();
            mMapView.getOverlays().clear();
        }
    }

    private class LoadLocationTask extends AsyncTask<Void, Void, List<Location>> {
        private ProgressDialog mProgressDialog;

        @Override
        protected void onPreExecute() {
            mProgressDialog = ProgressDialog.show(MainActivity.this,
                    "Invoke Service", "Loading location...");
        }

        @Override
        protected List<Location> doInBackground(Void... params) {
            try {
                // get all locations
                return mService.getLocations(-1);
            } catch (RemoteException e) {
                Log.e(TAG, e.getMessage(), e);
            }
            return null;
        }

        @Override
        protected void onPostExecute(List<Location> result) {
            mProgressDialog.cancel();
            mMapView.getOverlays().clear();

            if (result == null) {
                return;
            }

            Drawable marker = getResources().getDrawable(R.drawable.point_marker);
            marker.setBounds(
                    (int) (-marker.getIntrinsicWidth() / 2),
                    -marker.getIntrinsicHeight(),
                    (int) (marker.getIntrinsicWidth() / 2), 
                    0);

            MyLocation tracers = new MyLocation(marker);
            mMapView.getOverlays().add(tracers);

            for (Location location : result) {
                GeoPoint geoPoint = new GeoPoint(
                        (int) (location.getLatitude() * 1000000),
                        (int) (location.getLongitude() * 1000000));
                Log.i(TAG, "processing GeoPoint: " + geoPoint);
                OverlayItem item = new OverlayItem(geoPoint, "", "");
                tracers.add(item, false);
            }
            tracers.refresh();

            if (tracers.getItems().size() > 0) {
                GeoPoint center = LocationUtil.getCenterPoint(tracers.getItems(), 0);
                int latSpan = tracers.getLatSpanE6();
                int lngSpan = tracers.getLonSpanE6();
                Log.v("Overlays", "Lat span is " + latSpan);
                Log.v("Overlays", "Lng span is " + lngSpan);
                MapController mapController = mMapView.getController();
                mapController.animateTo(center);
                mapController.zoomToSpan((int) (latSpan * 1.5), (int) (lngSpan * 1.5));
            }
        }
    }

    /**
     * Periodically check remote service status
     * 
     * @author tqthe
     * 
     */
    private static class RefreshHandler extends Handler {
        private MainActivity mActivity;
        private boolean mActive = true;

        public RefreshHandler(MainActivity activity) {
            mActivity = activity;
        }

        @Override
        public void handleMessage(Message msg) {
            mActivity.updateServiceStatus();
            if (mActive) {
                requestNext();
            }
        }

        public void requestStop() {
            mActive = false;
        }

        public void requestRefresh() {
            Message message = Message.obtain();
            sendMessage(message);
        }

        private void requestNext() {
            Message message = Message.obtain();
            sendMessageDelayed(message, 5000);
        }
    }
}
